﻿using System;
using System.Collections.Generic;

using Whoever.Framework.Struct;
using Whoever.Framework.Base;

namespace Whoever.Patterns.Data
{
    public interface IRepository<TEntity> where TEntity : BusinessEntity, new()
    {
        TEntity GetById(TEntity entity);

        /// <summary>
        /// Get the entity correspondant to key values in view model sended
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        TEntity GetByKeys(ViewModel<TEntity> model);

        /// <summary>
        /// Get the entity correspondant to key values in entity sended
        /// </summary>
        /// <param name="keyValues"></param>
        /// <returns></returns>
        TEntity GetByKeys(TEntity entity);

        /// <summary>
        /// Get all items from database
        /// </summary>
        /// <returns></returns>
        IEnumerable<TEntity> GetAll();

        /// <summary>
        /// Get all items from database with paging
        /// </summary>
        /// <returns></returns>
        IEnumerable<TEntity> GetAll(ref Pager pager);

        /// <summary>
        /// Get all items and their relationships from database
        /// </summary>
        /// <returns></returns>
        IEnumerable<TEntity> GetAllRelated();

        /// <summary>
        /// Get all items and their relationships from database with paging
        /// </summary>
        /// <returns></returns>
        IEnumerable<TEntity> GetAllRelated(ref Pager pager);

        /// <summary>
        /// Get all related items loaded on entity relationship property
        /// </summary>
        /// <returns></returns>
        IEnumerable<TEntity> GetJustRelated();

        /// <summary>
        /// Get items filtering by a loaded ViewModel corresponding to an entity of current repository
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        IEnumerable<TEntity> GetFiltered(ViewModel<TEntity> model);

        /// <summary>
        /// Get items filtering by a loaded ViewModel corresponding to an entity of current repository with paging
        /// </summary>
        /// <param name="model"></param>
        /// <param name="pager"></param>
        /// <returns></returns>
        IEnumerable<TEntity> GetFiltered(ViewModel<TEntity> model, ref Pager pager);

        /// <summary>
        /// Get items filtering by a loaded entity corresponding to an entity of current repository (all not nullable field must be loaded)
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        IEnumerable<TEntity> GetFiltered(TEntity entity);

        /// <summary>
        /// Get items filtering by a loaded entity corresponding to an entity of current repository (all not nullable field must be loaded) with paging
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="pager"></param>
        /// <returns></returns>
        IEnumerable<TEntity> GetFiltered(TEntity entity, ref Pager pager);

        IEnumerable<TEntity> GetFiltered(Filter filter);

        IEnumerable<TEntity> GetFiltered(Filter filter, ref Pager pager);

        /// <summary>
        /// Get items filtering by a loaded viewmodel corresponding to an entity of current repository and their related entities
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        IEnumerable<TEntity> GetFilteredRelated(ViewModel<TEntity> model);

        /// <summary>
        /// Get items filtering by a loaded viewmodel corresponding to an entity of current repository and their related entities with paging
        /// </summary>
        /// <param name="model"></param>
        /// <param name="pager"></param>
        /// <returns></returns>
        IEnumerable<TEntity> GetFilteredRelated(ViewModel<TEntity> model, ref Pager pager);

        /// <summary>
        /// Insert a new item in database
        /// </summary>
        /// <param name="item"></param>
        int Insert(TEntity item);

        /// <summary>
        /// Insert a list of items in databaase
        /// </summary>
        /// <param name="items"></param>
        void Insert(IEnumerable<TEntity> items);

        /// <summary>
        /// Update a item from database
        /// </summary>
        /// <param name="item"></param>
        void Update(TEntity item);

        /// <summary>
        /// Update a list of items from database
        /// </summary>
        /// <param name="item"></param>
        void Update(IEnumerable<TEntity> items);

        /// <summary>
        /// Delete a item from database
        /// </summary>
        /// <param name="item"></param>
        void Delete(TEntity item);

        /// <summary>
        /// Delete a list of items from database
        /// </summary>
        /// <param name="item"></param>
        void Delete(IEnumerable<TEntity> items);

        /// <summary>
        /// Rollback all context changes
        /// </summary>
        void RollBack();

        /// <summary>
        /// Undo changes on item
        /// </summary>
        /// <param name="item"></param>
        void UndoChanges(TEntity item);

        /// <summary>
        /// Undo changes on a list of items
        /// </summary>
        /// <param name="items"></param>
        void UndoChanges(IEnumerable<TEntity> items);
    }
}
